package Cross;

import java.util.ArrayList;

import studentsGA.StudentsAlgorithm;
import GA.Algorithm;
import GA.Chromosome;
import GA.Cross;
import GA.Gene;

public class Ordinal extends Cross {

	public Ordinal(double crossProb, int chromosomeLenght) {
		super(crossProb, chromosomeLenght, ReplacementType.getBetters);
	}

	protected Chromosome[] cross(Chromosome parent1, Chromosome parent2) {
		// Convert parents to ordinal representation
		int[] ordParent1 = ordinal(parent1);
		int[] ordParent2 = ordinal(parent2);
		
		// Apply 1-point cross (classic cross)
		int crossPoint = Algorithm.random.nextInt(chromosomeLenght);		// Random point to cross
		int[] ordSon1 = new int[chromosomeLenght];
		int[] ordSon2 = new int[chromosomeLenght];
		// Primera parte del intercambio: 1 a 1 y 2 a 2
		for (int i = 0; i < crossPoint; i++){
			ordSon1[i] = ordParent1[i];
			ordSon2[i] = ordParent2[i];
		}
		// Segunda parte: 1 a 2 y 2 a 1
		for (int i = crossPoint; i < chromosomeLenght; i++){
			ordSon1[i] = ordParent2[i];
			ordSon2[i] = ordParent1[i];
		}
		
		// Create both sons
		Chromosome[] sons = new Chromosome[2];
		sons[0] = setOrdChromosome(parent1, ordSon1);
		sons[1] = setOrdChromosome(parent2, ordSon2);
		
		sons[0].setAptitude(sons[0].evaluate());
		sons[1].setAptitude(sons[1].evaluate());

		return sons;
	}

	private int[] ordinal(Chromosome chrom) {
		// Create an arraylist of indexes to ease the codification algorithm
		ArrayList<Integer> l = new ArrayList<Integer>();
		for (int i = 0; i < StudentsAlgorithm.N; i++)
			l.add(i);
		for (int i = StudentsAlgorithm.N; i < chromosomeLenght; i++)
			l.add(StudentsAlgorithm.N - i - 1);
		
		// Ordinal codification
		int[] ordGenes = new int[chromosomeLenght];
		for (int i = 0; i < chromosomeLenght; i++){
			int index = l.indexOf(chrom.getGene(i).id);
			ordGenes[i] = index;
			l.remove(index);
		}
		
		return ordGenes;
	}
	
	private Chromosome setOrdChromosome(Chromosome chrom, int[] ordinal){
		// Create an arraylist of indexes to ease the codification algorithm
		ArrayList<Integer> l = new ArrayList<Integer>();
		for (int i = 0; i < StudentsAlgorithm.N; i++)
			l.add(i);
		for (int i = StudentsAlgorithm.N; i < chromosomeLenght; i++)
			l.add(StudentsAlgorithm.N - i - 1);

		// Set new chromosome
		Chromosome ordChrom = chrom.clone();
		for (int i = 0; i < chromosomeLenght; i++){
			int index = l.get(ordinal[i]);
			ordChrom.setGene(i, getGene(index, chrom));
			l.remove(ordinal[i]);
		}
		
		return ordChrom;
	}

	private Gene getGene(int id, Chromosome chrom) {
		// Search for the gene in the chromosome
		for (int i = 0; i < chromosomeLenght; i++)
			if (chrom.getGene(i).id == id)
				return chrom.getGene(i).clone();	// return if found
		
		return null;	// return null otherwise
	}

}
